home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1998
/
MacHack 1998.toast
/
The Hacks!
/
AETEGizmo ƒ
/
Semaphores.h
< prev
Wrap
Text File
|
1998-06-21
|
6KB
|
147 lines
#ifndef __SEMAPHORES__
#define __SEMAPHORES__
#ifndef __THREADS__
#include <Threads.h>
#endif
//
// Convenience routines
//
Boolean TimeExpired(unsigned long currentTime, unsigned long startTime, unsigned long stopTime);
unsigned long CloserTick(unsigned long currentTime, unsigned long tick1, unsigned long tick2);
//========================================================================================
// CLASS TThreadIDQueue
//
// Keep track of a queue of ThreadIDs
//========================================================================================
class TThreadIDQueue
{
public:
TThreadIDQueue() : fThreadCount(0), fReservedSpace(0), fThreadQueue(nil) {};
~TThreadIDQueue();
OSErr Enqueue(ThreadID threadToAdd);
ThreadID Dequeue();
long QueuedThreads() { return fThreadCount; }
private:
OSErr InsureThreadQueueHasFreeSpace();
long fThreadCount;
long fReservedSpace;
ThreadID** fThreadQueue;
};
enum
{
kAnySemaphoreID = 0,
kNeverTimeoutSemaphore = 0x7FFFFFFF
};
//========================================================================================
// CLASS TSemaphore
//
// A semaphore consists of an owner thread and a list of blocked threads waiting to
// become the owner. When the semaphore is created, its resource count is specified
// to be either 0 or 1 (larger numbers could be supported if a list of owning threads
// was kept).
//
// A thread requests to become the owner by calling Grab, and relinquishes
// ownership by calling Release. Non-threads can get ownership of the semaphore by
// calling SetAvailable(false); in this case even though fOwningThread will be nil, the
// semaphore will still work correctly because fAvailable is false and thus other threads
// that grab the semaphore will block as they should.
//
// Semaphores are linked into a global list of all semaphores upon creation and removed
// upon deletion. Each semaphore has a unique ID (generated by a static method), and
// the global list can be searched for a given ID (via another static method).
//========================================================================================
class TSemaphore
{
// --- Methods -------------------------------------------------------------------------------------
public:
TSemaphore(long resourceCount = 1, long semaphoreID = kAnySemaphoreID);
protected:
virtual ~TSemaphore();
public:
static void InitializeGlobals();
static long NewUniqueSemaphoreID();
static TSemaphore* FindSemaphore(long semaphoreID, Boolean createIfNotFound = false, long resourceCount = 1);
static void Idle();
static void ThreadDied(ThreadID threadID);
static void SetDefaultTimeout(long newDefault);
static void SetDefaultMaxWait(long newMaxWait);
void ReleaseReference();
void Dispose();
long SemaphoreID() const;
OSErr Grab(ThreadID threadID = kCurrentThreadID);
void Release(ThreadID threadID = kCurrentThreadID);
ThreadID ReleaseOneThread();
void ReleaseAllThreads();
Boolean Available() const;
void SetAvailable(Boolean);
void ResetTimeoutTimer();
void AddGracePeriod(long gracePeriod);
void SetSemaphoreTimoutValue(long timeoutValue);
void SetSemaphoreMaxWaitTime(long timeoutValue);
long SemaphoreTimoutValue() { return fSemaphoreTimeoutValue; }
long SemaphoreMaxWaitTime() { return fSemaphoreMaxWaitTime; }
unsigned long TimeoutTick();
Boolean CheckIfTimerExpired(unsigned long currentTime);
void SemaphoreTimedOut();
protected:
void RemoveFromGlobalSemaphoreList();
// --- Fields -------------------------------------------------------------------------------------
private:
static TSemaphore* gFirstSemaphore; // Pointer to the first semaphore in the global list of all semaphores
static long gSemaphoreIDSequence; // The next available semaphore ID (used for assigning unique IDs)
static long gSemaphoreDefaultTimeout; // Default time to wait before timing out
static long gSemaphoreDefaultMaxWait; // Default maximum time to wait (exclusive of timer resets)
static unsigned long gLastTimeoutTest; // The last tick that we looked for timed-out semaphores
static unsigned long gLastIdleTick; // The last tick we got some idle time
static unsigned long gNextTimeoutTest; // Next tick to look for semaphores that have timed out
TSemaphore* fNextSemaphore; // Previous semaphore in the global list of all semaphores
TSemaphore* fPreviousSemaphore; // Next semaphore in the global list of all semaphores
ThreadID fOwnerThread; // The thread that currently owns this semaphore
TThreadIDQueue fBlockedThreads; // Queue of threads blocked on this semaphore
long fResourceCount; // The number of threads that may own this semaphore (0 or 1)
long fSemaphoreID; // The ID (usually unique) for this semaphore
long fOwnerCount; // The number of threads that currently own the semaphore (<= fResourceCount)
Boolean fDisposed; // True if someone disposed this semaphore
long fReferenceCount; // Count of blocked threads, to keep semaphore around after "deletion"
OSErr fFailOnWakeup; // If set, all threads fail with this error when they wake up
unsigned long fBlockStartTick; // TickCount at which first thread blocked on this semaphore
unsigned long fTimeoutTick; // The tick at which the semaphore will time out if timer
// is not recet
long fSemaphoreTimeoutValue; // How long to wait after every timer reset
long fSemaphoreMaxWaitTime; // The maximum number of ticks to wait before ignoring timer
// resets and just time out
};
inline void TSemaphore::SetDefaultTimeout(long newDefault) { gSemaphoreDefaultTimeout = newDefault; }
inline void TSemaphore::SetDefaultMaxWait(long newMaxWait) { gSemaphoreDefaultMaxWait = newMaxWait; }
inline unsigned long TSemaphore::TimeoutTick() { return fTimeoutTick; }
inline long TSemaphore::SemaphoreID() const { return fSemaphoreID; }
#endif